package cxydmmszl.chapter01.t009;

import java.util.Stack;

/**
 * <li style="color: red;">Prob</li>
 * 求最大子矩阵的大小
 * <li style="color: red;">Desc</li>
 * 给定一个矩阵 map，其中的值只有 0 和 1 两种，求其中全是 1 的所有矩形区域中，最大的矩形区域为 1 的数量。
 * <li style="color: red;">Link</li> CD16
 *
 * @author habitplus
 * @since 2021-08-27 10:34
 */
public class Main {
    /* 解题思路：
     * 1. 矩阵行数为 N，以每一行做切割，统计以当前行作为底的情况下，每个位置【垂直往上的连续 1 】的数量。
     *    使用高度数组 height 来表示。即：
     *      height[i][j] = map[i][j] = 0 ? height[j] + 1
     * 2. 对于每一次的切割，都利用更新后的 height 数组来求出以当前行为底的情况下，最大矩阵是什么。
     *    可以使用单调栈结构来求解
     */
    public int maxRecSize(int[][] map) {
        if (map == null || map.length == 0 || map[0].length == 0) {
            return 0;
        }

        int c = map[0].length;
        int[] height = new int[c];

        int maxArea = 0;
        for (int[] e : map) {
            // 计算 height；
            for (int j = 0; j < c; j++) {
                height[j] = e[j] == 0 ? 0 : height[j] + 1;
            }

            maxArea = Math.max(maxArea, maxRecFromBottom(height));
        }

        return maxArea;
    }

    private int maxRecFromBottom(int[] height) {
        /*
         * 使用单调栈结构求解
         */
        if (height == null || height.length == 0) {
            return 0;
        }

        Stack<Integer> monotonyStack = new Stack<>();
        int n = height.length,
                res = 0,
                j,
                k;

        for (int i = 0; i < n; i++) {
            while (!monotonyStack.isEmpty() && height[monotonyStack.peek()] >= height[i]) {
                j = monotonyStack.pop();
                k = monotonyStack.isEmpty() ? -1 : monotonyStack.peek();

                res = Math.max(res, (i - k - 1) * height[j]);
            }

            monotonyStack.push(i);
        }

        while (!monotonyStack.isEmpty()) {
            j = monotonyStack.pop();
            k = monotonyStack.isEmpty() ? -1 : monotonyStack.peek();

            res = Math.max(res, (n - k - 1) * height[j]);
        }

        return res;
    }


    public static void main(String[] args) {
        int[][] map = {
                {1, 0, 1,1},
                {1, 1, 1,1},
                {1, 1, 1,0}
        };

        System.out.println(new Main().maxRecSize(map));
    }
}
